package org.zebra.common.util;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.extra.spring.SpringUtil;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author zhanghongbin
 */
public final class SpringElUtil {

    private static final ExpressionParser parser = new SpelExpressionParser();
    private static final ParserContext parserContext = new TemplateParserContext();
    /**
     * bean解析器 用于处理 spel 表达式中对 bean 的调用
     */
    private static final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtil.getBeanFactory());

    private SpringElUtil() {}

    /**
     * @param el      同时支持 以#{}作为表达式开始和结束 或直接使用表达式
     * @param context 环境
     * @param type 类型
     * @param <T>  返回类型对象
     * @return T 泛型
     */
    public static <T> T parse(String el, StandardEvaluationContext context, Class<T> type) {
        //        示例：
        //        StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext();
        //        standardEvaluationContext.setVariable("userLog", userLog);
        //       1 获取 bean 属性 #{#userLog.id}
        //        standardEvaluationContext.setVariable("id", 1);
        //       2 获取 单个值 #{#id} 获取id的值
        //       3 调用spring对象方法 #{@abc.test(#versionName)} abc为服务名字 test为方法 #versionName为字段名称或固定值

        context.setBeanResolver(beanResolver);
        if (CharSequenceUtil.startWith(el, parserContext.getExpressionPrefix())
                && CharSequenceUtil.endWith(el, parserContext.getExpressionSuffix())) {
            return parser.parseExpression(el, parserContext).getValue(context, type);
        } else {
            return parser.parseExpression(el).getValue(context, type);
        }
    }

    public static StandardEvaluationContext getStandardEvaluationContext(String name, Object value) {
        StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext();
        standardEvaluationContext.setVariable(name, value);
        return standardEvaluationContext;
    }

    public static StandardEvaluationContext getStandardEvaluationContext(Map<String, Object> variable) {
        StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext();
        standardEvaluationContext.setVariables(variable);
        return standardEvaluationContext;
    }

    public static MethodBasedEvaluationContext getMethodBasedEvaluationContext(Method method, Object[] args) {
        return new MethodBasedEvaluationContext(null, method, args, new DefaultParameterNameDiscoverer());
    }
}
